<?php
/**
 * @package    panel
 * @subpackage panel.environment
 */
/**
 * Panel validation API
 * @author Dmitry Bakaleinik (code)
 */
abstract class panel__validate {

	/**
	 * Check value using multiple tests
	 * @throws panel__e__validation
	 * @param mixed          $_value_  (by ref)
	 * @param array|string   $_checks_ List of tests to perform
	 * @param string         $_name_   Field/Variable name
	 * @return mixed         $_value_  (by ref)
	 */
	static public function check(&$_value_, $_checks_ = array(), $_name_ = NULL) {

		$_checks_ = (array)  $_checks_;

		foreach( $_checks_ as $_check ) {

			switch($_check) {

			case "defined!":

				if( !isset($_value_) ) {

					if( panel__settings__environment::isDebug() ) {

						$e = new panel__e__exception("TRACE");
						panel__application::console($e);

					}	# if

					throw new panel__e__validation( isset_or($_name_, "variable"), "", "is not defined. ");

				}	# if

				break;

			case "numeric!":

				if( !is_numeric( self::check($_value_, array("defined!"), $_name_) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not numeric"); }

				break;

			case "boolean!":

				if( !is_bool( self::check($_value_, array("defined!"), $_name_) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not boolean"); }

				break;

			case "array!":

				if( !is_array( self::check($_value_, array("defined!"), $_name_ ) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not array"); }

				break;

			case "string!":

				if( !is_string( self::check($_value_, array("defined!"), $_name_ ) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not string"); }

				break;

			case "integer!":

				if( !is_integer( self::check($_value_, array("defined!"), $_name_ ) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not integer"); }

				break;

			case "float!":

				if( !is_float( self::check($_value_, array("defined!"), $_name_ ) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not float"); }

				break;

			case "scalar!":

				if( !is_scalar( self::check($_value_, array("defined!"), $_name_ ) ) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not float"); }

				break;

			case "!empty":

				self::check($_value_, array("defined!"), $_name_ );

				if( is_null($_value_) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is empty"); }

				if( is_array($_value_) && $_value_ == array() ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is empty"); }

				if( is_string($_value_) && $_value_ == "" ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is empty"); }

				break;

			case "!numeric":

				self::check($_value_, array("defined!"), $_name_ );

				if( is_numeric($_value_) ) {
					throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is numeric"); }

				break;

			case ">0":
				$_value_ = self::check( $_value_, array("numeric!", array("check" => ">x", "x" => 0)), isset_or($_name_, "variable") );
				break;

			case ">=0":
				$_value_ = self::check( $_value_, array("numeric!", array("check" => ">=x", "x" => 0)), isset_or($_name_, "variable") );
				break;

			case "<0":
				$_value_ = self::check( $_value_, array("numeric!", array("check" => "<x", "x" => 0)), isset_or($_name_, "variable") );
				break;

			case "<=0":
				$_value_ = self::check( $_value_, array("numeric!", array("check" => "<=x", "x" => 0)), isset_or($_name_, "variable") );
				break;

			case "~string":
				$_value_ = (string) isset_or($_value_, "");
				break;

			case "~array":
				$_value_ = (array) isset_or($_value_, array());
				break;

			case "~float":
				$_value_ = (float) isset_or($_value_, 0);
				break;

			case "~integer":
				$_value_ = (integer) isset_or($_value_, 0);
				break;

			case "~boolean":
				$_value_ = (bool) isset_or($_value_, false);
				break;

			case "|mysqlescape":
				$_value_ = mysql_escape_string( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|trim":
				$_value_ = trim( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|lower":
				$_value_ = strtolower( self::check($_value_, array("string!"), isset_or($_name_, "variable") ) );
				break;

			case "|upper":
				$_value_ = strtoupper( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|slashes":
				$_value_ = addslashes( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|!slashes":
				$_value_ = stripslashes( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|urlencode":
				$_value_ = urlencode( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|!urlencode":
				$_value_ = urldecode( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|htmlencode":
				$_value_ = htmlentities( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case "|!htmlencode":
				$_value_ = html_entity_decode( self::check($_value_, array("scalar!", "~string"), isset_or($_name_, "variable") ) );
				break;

			case is_array($_check):

				switch( isset_or_error($_check["check"]) ) {

				case "|replace":

					$_value_ = str_replace(
						isset_or_error($_check["search"]),
						isset_or_error($_check["replace"]),
						self::check($_value_, array("scalar!"), isset_or($_name_, "variable") )
					);

					break;

				case "|ireplace":

					$_value_ = str_ireplace(
						isset_or_error($_check["search"]),
						isset_or_error($_check["replace"]),
						self::check($_value_, array("scalar!"), isset_or($_name_, "variable") )
					);

					break;

				case "|iconv":

					$_value_ = iconv(
						isset_or_error($_check["in"]),
						isset_or_error($_check["out"]),
						self::check($_value_, array("scalar!"), isset_or($_name_, "variable") )
					);

					break;

				case "ifempty=x":

					if( empty($_value_) ) {
						$_value_ = isset_or_error($_check["x"]); }

					break;

				case "maxlength=x":

					if( strlen( self::check($_value_, array("scalar!"), $_name_) ) > isset_or_error($_check["x"]) ) {
						throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "exceed maximal length {$_check["x"]}"); }

					break;

				case ">x":

					if( !( $_value_ > isset_or_error($_check["x"])) ) {
						throw new panel__e__validation(isset_or($_name_, "variable"), $_value_, "is not > {$_check["x"]}"); }

					break;

				case ">=x":

					if( !( $_value_ >= isset_or_error($_check["x"])) ) {
						throw new panel__e__validation(isset_or($_name_, "variable"), $_value_, "is not > {$_check["x"]}"); }

					break;

				case "<x":

					if( !( $_value_ < isset_or_error($_check["x"])) ) {
						throw new panel__e__validation(isset_or($_name_, "variable"), $_value_, "is not < {$_check["x"]}"); }

					break;

				case "<=x":

					if( !( $_value_ <= isset_or_error($_check["x"])) ) {
						throw new panel__e__validation(isset_or($_name_, "variable"), $_value_, "is not <= {$_check["x"]}"); }

					break;

				case "a..b":

					if( !( $_value_ >= isset_or_error($_check["a"]) && $_value_ <= isset_or_error($_check["b"]) ) ) {
						throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not in range '{$_check["a"]}..{$_check["b"]}'"); }

					break;

				case "!a..b":

					if( $_value_ >= isset_or_error($_check["a"]) && $_value_ <= isset_or_error($_check["b"]) ) {
						throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "in range '{$_check["a"]}..{$_check["b"]}'"); }

					break;

				case "invalues":

					if( !in_array($_value_, isset_or_error($_check["values"]), true) ) {
						throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "is not in range of values"); }

					break;

				case "!invalues":

					if( in_array($_value_, isset_or_error($_check["values"]), true) ) {
						throw new panel__e__validation( isset_or($_name_, "variable"), $_value_, "in range of values"); }

					break;

				case "regexp":

					$_value_ = self::check($_value_, array("scalar!", "~string"), $_name_);

					if( !preg_match( isset_or_error($_check["pattern"]), $_value_, $matches) ) {
						throw new panel__e__validation(
							isset_or($_name_, "variable"), $_value_,
							isset_or($_check["message"], "dosn`t match with regexp mask '{$_check["pattern"]}'")
						);

					}	# if

					if( !isset($matches[0]) || $matches[0] != $_value_ ) {

						throw new panel__e__validation(
							isset_or($_name_, "variable"), $_value_,
							isset_or($_check["message"], "dosn`t match with regexp mask '{$_check["pattern"]}'")
						);

					}	# if

					break;

				}	# switch

				break;

			case "[id]":
				$_value_ = self::check( $_value_, array("defined!", "!empty", "|trim", "numeric!", "~integer", ">0"), isset_or($_name_, "ID") );
				break;

			case "[id0]":
				$_value_ = self::check( $_value_, array("defined!", "!empty", "|trim", "numeric!", "~integer"), isset_or($_name_, "ID") );
				break;

			case "[text]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string", "|trim",
						array(
							"check"   => "regexp",
							"pattern" => "/^[\na-zA-Z0-9\s\{\}\[\]\<\>\#\/\^\$\!\?\@\®\%\&\*\.\:\;\,\(\)\+\=\_\-\'\"]+$/im",
							"message" => "allowed A-Z, 0-9, punctuation signs."
						),
						array(
							"check" => "|iconv",
							"in"    => "UTF-8",
							"out"   => "ISO-8859-1"
						)
					),
					isset_or($_name_, "variable")
				);

				break;

			case "[boolean]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "~boolean",
						array("check" => "invalues", "values" => array(TRUE, FALSE, 1, 0))
					),
					isset_or($_name_, "Active")
				);

				break;

			case "[ip]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string", "|trim",
						array("check" => "regexp", "pattern" => "/^(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])$/")
					),
					isset_or($_name_, "IP")
				);

				break;

			case "[hostname]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string", "|trim", "|lower",
						array("check" => "regexp", "pattern" => "/[a-zA-Z0-9\_\:\/\.\-]+/")
					),
					isset_or($_name_, "Hostname")
				);

				break;

			case "[url-r]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string", "|trim", "|lower",
						array(
							"check"   => "regexp",
							"pattern" => "/^([a-zA-Z0-9\_\-]+\.)?[a-zA-Z0-9\-\_]+$/",
							"message" => "allowed like some_url.php"
						)
					),
					isset_or($_name_, "variable")
				);

				break;

			case "[url-ar]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string", "|trim", "|lower",
						array(
							"check"   => "regexp",
							"pattern" => "/^((http\:\/\/)([a-zA-Z0-9\_\-]+[\.])+[a-zA-Z0-9]+|([a-zA-Z0-9\_\-]+\.)?[a-zA-Z0-9]+)$/",
							"message" => "allowed like http://domain.com or some_url.php"
						)
					),
					isset_or($_name_, "variable")
				);

				break;

			case "[allow-empty]":

				if( !isset($_value_) || empty($_value_) ) {
					return $_value_; }

				break;

			case "[entity-type-panel-acl]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "~string", "|trim",
						array(
							"check"   => "invalues",
							"values"  => array(
								panel__model__entities::TYPE__PANEL__ACL__USER
							),
						)
					),
					isset_or($_name_, "Panel ACL Entity Type")
				);

				break;

			case "[asc-desc]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "~string", "|upper",
						array(
							"check"   => "invalues",
							"values"  => array("ASC", "DESC")
						)
					),
					isset_or($_name_, "ASC/DESC")
				);

				break;

			case "[login]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string", "|lower",
						array(
							"check"   => "regexp",
							"pattern" => "/^[a-z0-9\_]+$/",
							"message" => "Allowed only characters: a-z, 0-9, _"
						)
					),
					isset_or($_name_, "Login")
				);

				break;

			case "[password]":

				$_value_ = self::check(
					$_value_,
					array(
						"defined!", "!empty", "scalar!", "~string",
						array(
							"check"   => "regexp",
							"pattern" => "/^[a-zA-Z0-9]+$/",
							"message" => "Allowed only characters: a-z, 0-9"
						)
					),
					isset_or($_name_, "Password")
				);

				break;

			default:

				p()->console(
					"Unknown validation method: " .
					var_export($_check, true)
				);

				break;

			}	# switch

		}	# foreach

		return $_value_;

	}	# Function

}	# Class

/* EOF */